import Bridge from "@src/bridge";
import Taro from "@tarojs/taro";
import axios, { AxiosRequestConfig, Canceler } from "axios";
import { getGlobalData, setGlobalData } from "..";
import { getStorage } from "../storage";

export type CustomRequestConfig = AxiosRequestConfig&{abort?:Canceler}

let requestCancelHandler:Canceler[] = [];

const axiosIns = axios.create({
    baseURL: BASE_URL,
    timeout: 5000,
});


axiosIns.defaults.headers.post["Content-type"] = "application/json;charset=UTF-8";

const retry = 4;
const retryDelay = 1000;

export const cancelAllRequest = ()=>{
    requestCancelHandler.forEach(cancel=>{
        cancel();
    });
    requestCancelHandler = [];
};

const refreshToken = ()=>{
    return axiosIns({
        method:"post",
        data:{
            refresh:getGlobalData("refreshToken")
        },
        url:"/api/token/refresh/"
    }).then((res)=>{
        // TODO 判断是否正确
        console.log(res.data);
        setGlobalData("accessToken",res.data.access);
        Taro.setStorage({
            key:"accessToken",
            data:JSON.stringify(res.data.access)
        });
        return res.data.access;
    });
};

axiosIns.interceptors.request.use(async (config:CustomRequestConfig) => {
    if (!config.headers) {
        config.headers = {};
    }
    let accessToken = getGlobalData("accessToken");
    if(!accessToken){
        accessToken = await getStorage("accessToken");
        setGlobalData("accessToken",accessToken);
    }
    config.headers["Authorization"] = `Bearer ${accessToken}`;
    config.cancelToken = new axios.CancelToken(c=>{
        config.abort = c;
        requestCancelHandler.push(c);
    });
    return config;
}, err => Promise.reject(err));

axiosIns.interceptors.response.use(response => {
    switch (response.data.code) {
        case -1:
            break;
        default:
            break;
    }
    return response;
}, err => {
    const config = err.config;
    if (err.code === "ECONNABORTED" || err.message.includes("timeout")) {
        config.__retryCount = config.__retryCount || 0;

        // 判断是否超过总重试次数
        if (config.__retryCount >= retry) {
            // 返回错误并退出自动重试
            return Promise.reject(err);
        }
        
        config.__retryCount ++;

        var backoff = new Promise<void>(function (resolve) {
            setTimeout(function () {
                resolve();
            }, retryDelay);
        });
    
        // 返回重试请求
        return backoff.then(function () {
            return axiosIns(config);
        });

    }
    if(err.response){
        switch (err.response.status) {
            case 401:
                console.log("我被执行了",err.config.url);
                if (!config.url?.match(/refresh/) && getGlobalData("refreshToken")) {
                    return refreshToken().then(()=>{
                        return axiosIns(config);
                    });
                } else {
                    return new Promise<void>((resolve,reject)=>{
                        Bridge.Instance.login({
                            onSuccess(res){
                                setGlobalData("accessToken",res.data.access);
                                setGlobalData("refreshToken",res.data.refresh);
                                Taro.setStorage({
                                    key:"accessToken",
                                    data:JSON.stringify(res.data.access)
                                });
                                Taro.setStorage({
                                    key:"refreshToken",
                                    data:JSON.stringify(res.data.refresh)
                                });
                                resolve();
                            },
                            onFail(){
                                reject();
                            }
                        });
                    }).then(()=>{
                        return axiosIns(config);
                    },()=>{
                        return Promise.reject(err.response?.data);
                    });
                }
    
            default:
                Taro.showToast({
                    title: err.response?.data?.message || err.message,
                    icon: "error"
                });
                return Promise.reject(err);
        }
    }else{
        return Promise.reject(err);
    }
    
});


export default axiosIns;